import Relationship from "ol/extent/Relationship";
import { animationUpdate } from "x-myutils/animationUpdate"
export function tween(obj) {
    return new TweenObject(obj);
}

let inited = false;
export function initTween() {
    if (inited) {
        return;
    }
    animationUpdate(update);
    inited = true;
}
function update(dt) {
    for (let i = 0; i < tweenObjList.length; i++) {
        const item = tweenObjList[i];
        if (item.completed) {
            tweenObjList.splice(i, 1);
            i--;
        } else {
            item.update(dt);
        }
    }
}

const tweenObjList = [];
class TweenObject {
    constructor(obj) {
        this.obj = obj;
        this.tweenList = [];
        this.completed = false;
        this.isLoop = false;
        tweenObjList.push(this);
        this.curIndex = 0;
    }

    loop() {
        this.isLoop = true;
        return this;
    }

    callback(func) {
        this.tweenList.push(new Callback(func));
        return this;
    }

    delay(duration) {
        this.tweenList.push(new Delay(duration));
        return this;
    }


    destroy() {
        this.completed = true;
    }

    to(data, duration, addOperator) {
        this.tweenList.push(new LinearTween(this.obj, data, duration, addOperator));
        return this;
    }

    complete() {
        if (this.isLoop) {
            this.curIndex = 0;
            for (const i of this.tweenList) {
                i.reset();
            }
        } else {
            this.completed = true;
            delete this.tweenList;
            delete this.obj;
        }
    }

    update(dt) {
        const list = this.tweenList;

        if (list.length <= 0 || this.completed) {
            this.completed = true;
            return;
        }

        const cur = list[this.curIndex];
        if (!cur) {
            this.complete();
            return;
        }

        if (!cur.completed) {
            cur.update(dt);
        } else {
            this.curIndex++;
            this.update(dt);
        }
    }
}

class Tween {
    update(dt) {
    }

    complete() {
        this.completed = true;
    }

    reset() {
        this.completed = false;
    }
}

class Callback extends Tween {
    constructor(func) {
        super();
        this.func = func;
    }

    update() {
        this.func();
        this.completed = true;
    }
}

const frameDuration = 1000 / 60;
class LinearTween extends Tween {
    constructor(obj, data, duration, addOperator) {
        super();
        this.maxCount = Math.round(duration / frameDuration);
        this.count = 0;
        this.obj = obj;
        this.completed = false;
        this.addOperator = addOperator;

        this.updateList = [];
        for (const key in data) {
            const targetValue = data[key], curValue = obj[key];
            if (!curValue) {
                continue;
            }

            const deltaValue = targetValue - curValue;
            this.updateList.push({
                key: key,
                dv: deltaValue / this.maxCount
            });
        }
    }

    reset() {
        super.reset();
        this.count = 0;
    }

    update() {
        const that = this;
        if (that.count >= that.maxCount) {
            this.complete();
            return;
        }

        for (let i = 0; i < that.updateList.length; i++) {
            const item = that.updateList[i];
            if (this.addOperator) {
                that.obj[item.key] = this.addOperator(that.obj[item.key], item.dv);
            } else {
                that.obj[item.key] += item.dv;
            }
        }

        that.count++;
    }
}

class Delay extends Tween {
    constructor(duration) {
        super();
        this.duration = duration;
        this.timer = 0;
    }
    update(dt) {
        if (this.timer >= this.duration) {
            this.complete();
        } else {
            this.timer += dt;
        }
    }

    reset() {
        super.reset();
        this.timer = 0;
    }
}